package com.meizi.codegenerate.generate.clien.ui.request.query;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.Modifier;
import com.github.javaparser.ast.NodeList;
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
import com.github.javaparser.ast.type.ClassOrInterfaceType;
import com.github.javaparser.utils.StringEscapeUtils;
import com.meizi.codegenerate.constant.AnnotationSettingValueConstant;
import com.meizi.codegenerate.constant.CharacteristicConstant;
import com.meizi.codegenerate.constant.JavaClassNameConstant;
import com.meizi.codegenerate.constant.TableNameConstant;
import com.meizi.codegenerate.entity.ColumnsEntity;
import com.meizi.codegenerate.entity.ProjectPositionEntity;
import com.meizi.codegenerate.entity.TablesEntity;
import com.meizi.codegenerate.enums.ColumnDataTypeEnum;
import com.meizi.codegenerate.enums.ColumnToImportEnum;
import com.meizi.codegenerate.enums.IndexesEnum;
import com.meizi.codegenerate.packagegenerate.PackageGenerate;
import com.meizi.codegenerate.tool.page.PageParam;
import com.meizi.codegenerate.utils.AnnotationUtils;
import com.meizi.codegenerate.utils.AttributeConvertUtils;
import com.meizi.codegenerate.utils.ColumnUtils;
import com.meizi.codegenerate.utils.JDBCUtils;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;

/**
 * @author pc
 * @date 2023/7/27 - 14:21 - 星期四
 * @project lambda
 * @package com.meizi.codegenerate.generate.clien.ui.request.query
 * @by GGbomd猪猪侠
 */
@Slf4j
public class PageParamQueryBodyGenerate {

    /**
     * 创建 PageParamQueryBody 请求实体
     * @throws IOException
     */
    public static void createPageParamQueryBody () throws IOException {

        // 在相应的路径下创建对应的文件
        ProjectPositionEntity projectPosition = PackageGenerate.getProjectPosition();
        String requesterQueryUrl = PackageGenerate.obtainQueryUrl(projectPosition);

        // 获取要生成对应的表名
        List<String> tableNameList = TableNameConstant.getTableNameList();
        LinkedHashMap<String, Object> map = new LinkedHashMap<>();
        for (String tableName : tableNameList) {
            map.clear();

            // 获取数据表的字段名字类型等信息
            List<ColumnsEntity> columnsEntities = JDBCUtils.queryColumns(tableName);
            HashMap<String, String> hashMap = ColumnUtils.columnTypeToImport
                    (ColumnUtils.mapColumnDateType(columnsEntities));
            log.info("获取数据库字段类型对应的映射类型 hashMap = {}", hashMap);

            // 获取对数据表得备注信息
            TablesEntity tablesComment = JDBCUtils.queryTablesComment(tableName);
            // 获取对应数据表字段备注信息
            List<ColumnsEntity> columnsCommentList = JDBCUtils.queryColumnsComment(tableName);

            //获取requesterQuery java类名
            String className = AttributeConvertUtils.tableNameToJava
                    (tableName, TableNameConstant.TABLE_PREFIX, true)
                    + JavaClassNameConstant.PAGE_PARAM_QUERY_BODY;
            // 获取完成的文件路径创建文件
            String fullPath = requesterQueryUrl + className + TableNameConstant.JAVA;
            log.info("创建 PageParamQuery 路径  fullPath = {}", fullPath);

            CompilationUnit compilationUnit = new CompilationUnit();
            // 添加package
            compilationUnit.setPackageDeclaration(PackageGenerate.requesterQueryPackage(projectPosition));
            // 导入import
            for (String key : hashMap.keySet()) {
                String value = hashMap.get(key);
                compilationUnit.addImport(value);
            }

            // 添加类文件
            ClassOrInterfaceDeclaration declaration = compilationUnit.addClass(className).setPublic(true);
            // 及继承类
            declaration.addExtendedType(PageParam.class);
            //添加类级别注释
            declaration.setJavadocComment(tablesComment.getTableComment());
            // 添加类级别注解
            declaration.addAnnotation(Data.class);

            // 添加 @EqualsAndHashCode(callSuper=false)
            map.put(AnnotationSettingValueConstant.CALL_SUPER, AnnotationSettingValueConstant.SET_CALL_SUPER_VALUE);
            declaration.addAnnotation(AnnotationUtils.setAnnotation(EqualsAndHashCode.class, new NodeList<>(),
                    map));
            map.clear();

            // 添加@ApiModel()
            map.put(AnnotationSettingValueConstant.APIMODEL_VALUE, className);
            map.put(AnnotationSettingValueConstant.APIMODEL_DESCRIPTION, tablesComment.getTableComment());
            declaration.addAnnotation(AnnotationUtils.setAnnotation(ApiModel.class, new NodeList<>(),
                    map));
            map.clear();

            // 实例化属性 字段类型
            for (ColumnsEntity columnsEntity : columnsEntities) {
                // 字段备注信息
                for (ColumnsEntity columnComment : columnsCommentList) {
                    if (columnComment.getField().equals(columnsEntity.getField())) {

                        map.put(AnnotationSettingValueConstant.APIMODELPROPERTY_VALUE, StringEscapeUtils.escapeJava(columnComment.getColumnComment()));
                        if (StringUtils.isNotBlank(columnComment.getColumnComment()) &&
                                columnComment.getColumnComment().contains(CharacteristicConstant.TABLELOGIC)) {

                            declaration.addField(
                                    ColumnDataTypeEnum.from(columnsEntity.getType()).getDesc(),
                                    AttributeConvertUtils.columnNameToJava(columnsEntity.getField(), TableNameConstant.COLUMN_PREFIX, false),
                                    Modifier.Keyword.PRIVATE
                            ).setJavadocComment(columnComment.getColumnComment())
                                    .addAnnotation(AnnotationUtils.setAnnotation(ApiModelProperty.class, new NodeList<>(), map))
                                    .addAnnotation(JsonIgnore.class);

                        } else {

                            declaration.addField(
                                    ColumnDataTypeEnum.from(columnsEntity.getType()).getDesc(),
                                    AttributeConvertUtils.columnNameToJava(columnsEntity.getField(), TableNameConstant.COLUMN_PREFIX, false),
                                    Modifier.Keyword.PRIVATE
                            ).setJavadocComment(columnComment.getColumnComment())
                                    .addAnnotation(AnnotationUtils.setAnnotation(ApiModelProperty.class, new NodeList<>(), map));

                        }

                        // 是主键 生成对应的list
                        if (columnsEntity.getKey().equals(IndexesEnum.PRI.getValue())) {
                            map.clear();
                            map.put(AnnotationSettingValueConstant.APIMODELPROPERTY_VALUE, StringEscapeUtils.escapeJava(columnComment.getColumnComment() + "List列表"));
                            // 设置List嵌套
                            ClassOrInterfaceType listType = new ClassOrInterfaceType(List.class.getSimpleName());
                            listType.setTypeArguments(new ClassOrInterfaceType(ColumnDataTypeEnum.from(columnsEntity.getType()).getDesc().getSimpleName()));

                            declaration.addField(
                                    listType,
                                    AttributeConvertUtils.columnNameToJava(columnsEntity.getField() + "List", TableNameConstant.COLUMN_PREFIX, false),
                                    Modifier.Keyword.PRIVATE
                            ).setJavadocComment(columnComment.getColumnComment() + "List")
                                    .addAnnotation(AnnotationUtils.setAnnotation(ApiModelProperty.class, new NodeList<>(), map));
                        }

                        // 是时间类型属性生成 Gt大于> Lt小于<
                        // 大于等于 Gte>=  Lte小于等于<=
                        if (StringUtils.isNotBlank(columnsEntity.getType()) &&
                                (columnsEntity.getType().contains(ColumnToImportEnum.DATETIME.getValue()) ||
                                        columnsEntity.getType().contains(ColumnToImportEnum.DATE.getValue())) ) {

                            createGtLt(map, columnsEntity, columnComment, "Gt", "（大于>开始）", declaration);
                            createGtLt(map, columnsEntity, columnComment, "Lt", "（小于<结束）", declaration);
                            createGtLt(map, columnsEntity, columnComment, "Gte", "（大于等于>=开始）", declaration);
                            createGtLt(map, columnsEntity, columnComment, "Lte", "（小于等于<=结束）", declaration);

                        }

                        map.clear();
                    }
                }
            }

            log.info("生成pageParam接口 compilationUnit = {}", compilationUnit.toString());


            /**
             * 把字符串写入文件
             * 参数1：需要写入的文件，如果文件不存在，将自动创建。  参数2：需要写入的内容
             * 参数3：编码格式     参数4：是否为追加模式（ ture: 追加模式，把字符串追加到原内容后面）
             */
            FileUtils.writeStringToFile(new File(fullPath), compilationUnit.toString(), "UTF-8", false);
        }
    }

    private static void createGtLt(LinkedHashMap<String, Object> map, ColumnsEntity columnsEntity, ColumnsEntity columnComment,
                                   String gt, String value, ClassOrInterfaceDeclaration declaration) {
        map.clear();
        map.put(AnnotationSettingValueConstant.APIMODELPROPERTY_VALUE, StringEscapeUtils.escapeJava(columnComment.getColumnComment() + value));
        String toJava = AttributeConvertUtils.columnNameToJava(columnsEntity.getField(),
                TableNameConstant.COLUMN_PREFIX, false);
        declaration.addField(
                        ColumnDataTypeEnum.from(columnsEntity.getType()).getDesc(),
                        toJava + gt,
                        Modifier.Keyword.PRIVATE
                ).setJavadocComment(columnComment.getColumnComment())
                .addAnnotation(AnnotationUtils.setAnnotation(ApiModelProperty.class, new NodeList<>(), map));
    }
}
